/**
 * 
 */
package profile.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.runners.model.Statement;


/**
 * @author ductrung.tran
 *
 */
@Aspect
public abstract class JunitRunnerWorkAroundAspect {

	static class AfterClassStatement extends Statement {

		private Statement next;
		
		public AfterClassStatement(Statement next) {
			this.next = next;
		}
		
		@Override
		public void evaluate() throws Throwable {
			try {
				next.evaluate();
			} finally {
				long expriredTime = System.currentTimeMillis() + 30000;
				MethodCallRepository resultHandler = MethodCallRepository.getInstance();
				while (resultHandler != null /* null when no store is tested */
						&& !resultHandler.isWorkerThreadTerminated() 
						&& System.currentTimeMillis() < expriredTime) {
					Thread.sleep(1000);
				}
			}
			
		}
		
	}
	
	@Pointcut
	public abstract void withAfterClassesPointcut();
	
	@Around("withAfterClassesPointcut()")
	public Object withAfterClassesAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		Object result = joinPoint.proceed();
		if (!(result instanceof AfterClassStatement)) {
			return wrapStatement(result);
		}
		return result;
	}

	private Object wrapStatement(Object result) {
		return new AfterClassStatement((Statement) result);
	}
}
